/*
 * Copyright (c) 2009 Jostein Austvik Jacobsen
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package no.infotavle;

import java.awt.Rectangle;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class Settings {
	
	// Name or location displayed in upper left corner
	public String name;
	
	// Size and position of the graphics. Everything outside this will be black
	public Rectangle offset;
	
	// URL to XML weather data from yr.no
	public String yr;
	
	// Which stops to get realtime data from, and which parts of that data that are to be displayed
	public ArrayList<Integer> stop_id = new ArrayList<Integer>();
	public ArrayList<String> stop_name = new ArrayList<String>();
	public ArrayList<Date> stop_updated = new ArrayList<Date>();
	public ArrayList<ArrayList<Integer>> stop_platform_nr = new ArrayList<ArrayList<Integer>>();
	public ArrayList<ArrayList<String>> stop_platform_name = new ArrayList<ArrayList<String>>();
	public ArrayList<ArrayList<ArrayList<Integer>>> stop_platform_include = new ArrayList<ArrayList<ArrayList<Integer>>>();
	public ArrayList<ArrayList<ArrayList<Integer>>> stop_platform_exclude = new ArrayList<ArrayList<ArrayList<Integer>>>();
	
	// Twitter feeds
	public String twitter_username;
	public String twitter_password;
	public ArrayList<String> feed_img = new ArrayList<String>();
	
	public Settings(String filename) {
		try {
			Date now = new Date();
			File file = new File(filename);
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document document = builder.parse(file);
			
			NodeList root = document.getChildNodes();
			if (root.getLength() <= 0) {
				throw new Exception("No XML-nodes found");
			}
			NodeList settings = root.item(0).getChildNodes(); // Assume there's only one
			
			offset = new Rectangle(49,20,926,728);
			
			for (int docpart = 0; docpart < settings.getLength(); docpart++) {
				Node docNode = settings.item(docpart);
				
				// Name of this box, for instance the adress you live at
				if (docNode.getNodeName().equalsIgnoreCase("name")) {
					this.name = docNode.getTextContent();
				}
				
				// Size of display
				if (docNode.getNodeName().equalsIgnoreCase("offset")) {
					try {
						NamedNodeMap attr = docNode.getAttributes();
						if (attr.getNamedItem("x") != null)
							offset.x = Integer.parseInt(attr.getNamedItem("x").getTextContent());
						if (attr.getNamedItem("y") != null)
							offset.y = Integer.parseInt(attr.getNamedItem("y").getTextContent());
					} catch (Exception e) {
						throw new Exception("Failed to determine offset (x,y): "+e.toString());
					}
				}
				if (docNode.getNodeName().equalsIgnoreCase("size")) {
					try {
						NamedNodeMap attr = docNode.getAttributes();
						if (attr.getNamedItem("width") != null)
							offset.width = Integer.parseInt(attr.getNamedItem("width").getTextContent());
						if (attr.getNamedItem("height") != null)
							offset.height = Integer.parseInt(attr.getNamedItem("height").getTextContent());
					} catch (Exception e) {
						throw new Exception("Failed to determine size (width,height): "+e.toString());
					}
				}
				
				// Weather data from yr.no
				if (docNode.getNodeName().equalsIgnoreCase("yr")) {
					this.yr = docNode.getTextContent();
				}
				
				// Public transport data from trafikanten.no
				else if (docNode.getNodeName().equalsIgnoreCase("trafikanten")) {
					NodeList stops = docNode.getChildNodes();
					
					for (int si = 0; si < stops.getLength(); si++) {
						if (!stops.item(si).getNodeName().equalsIgnoreCase("stop"))
							continue;
						int s = stop_id.size();
						
						NamedNodeMap attr = stops.item(si).getAttributes();
						
						try {
							stop_id.add(Integer.parseInt(attr.getNamedItem("id").getNodeValue()));
						} catch (Exception e) {
							throw new Exception("Failed to determine id of stop: "+e.toString());
						}
						try {
							stop_name.add(attr.getNamedItem("name").getNodeValue());
						} catch (Exception e) {
							throw new Exception("Failed to determine id of stop: "+e.toString());
						}
						stop_updated.add(now);
						stop_platform_nr.add(new ArrayList<Integer>());
						stop_platform_name.add(new ArrayList<String>());
						stop_platform_include.add(new ArrayList<ArrayList<Integer>>());
						stop_platform_exclude.add(new ArrayList<ArrayList<Integer>>());
						
						NodeList platforms = stops.item(si).getChildNodes();
						for (int pi = 0; pi < platforms.getLength(); pi++) {
							if (!platforms.item(pi).getNodeName().equalsIgnoreCase("platform"))
								continue;
							int p = stop_platform_nr.get(s).size();
							
							attr = platforms.item(pi).getAttributes();
							
							try {
								stop_platform_nr.get(s).add(Integer.parseInt(attr.getNamedItem("nr").getTextContent()));
							} catch (Exception e) { throw new Exception("Failed to parse platform nr: "+e.toString()); }
							try {
								stop_platform_name.get(s).add(attr.getNamedItem("name").getTextContent());
							} catch (Exception e) { throw new Exception("Failed to find platform name: "+e.toString()); }
							
							stop_platform_include.get(s).add(new ArrayList<Integer>());
							stop_platform_exclude.get(s).add(new ArrayList<Integer>());
							
							if (attr.getNamedItem("include") != null) {
								try {
									String csv = attr.getNamedItem("include").getTextContent();
									String[] values = csv.split(",");
									for (int v = 0; v < values.length; v++) {
										stop_platform_include.get(s).get(p).add(Integer.parseInt(values[v]));
									}
								} catch (Exception e) {
									throw new Exception("Failed to parse platform includes: "+e.toString());
								}
							}
							
							else if (attr.getNamedItem("exclude") != null) {
								try {
									String csv = attr.getNamedItem("exclude").getTextContent();
									String[] values = csv.split(",");
									for (int v = 0; v < values.length; v++) {
										stop_platform_exclude.get(s).get(p).add(Integer.parseInt(values[v]));
									}
								} catch (Exception e) {
									throw new Exception("Failed to parse platform excludes: "+e.toString());
								}
							}
						}
					}
				}
				
				// Twitter feeds
				else if (docNode.getNodeName().equalsIgnoreCase("twitter")) {
					NamedNodeMap feed = docNode.getAttributes();
					
					try {
						twitter_username = feed.getNamedItem("username").getTextContent();
						twitter_password = feed.getNamedItem("password").getTextContent();
					} catch (Exception e) {
						throw new Exception("Failed to fetch username or password from twitter feed");
					}
				}
			}
		} catch (Exception e) {
			System.err.println(e.toString());
			e.printStackTrace();
		}
	}
	
	// Useful for debugging
	public void printDataTree() {
		System.out.println("name: "+name);
		
		System.out.println("yr: "+yr);
		
		System.out.println("stops:");
		for (int s = 0; s < stop_id.size(); s++) {
			System.out.println("\tid: "+stop_id.get(s));
			System.out.println("\t name: "+stop_name.get(s));
			System.out.println("\t updated: "+stop_updated);
			System.out.println("\t platforms:");
			for (int p = 0; p < stop_platform_nr.size(); p++) {
				System.out.println("\t\tnr: "+stop_platform_nr.get(s).get(p));
				System.out.println("\t\t name: "+stop_platform_name.get(s).get(p));
				System.out.println("\t\t include:");
				for (int i = 0; i < stop_platform_include.get(s).get(p).size(); i++) {
					System.out.println("\t\t\t"+stop_platform_include.get(s).get(p).get(i));
				}
				System.out.println("\t\t exclude:");
				for (int e = 0; e < stop_platform_exclude.get(s).get(p).size(); e++) {
					System.out.println("\t\t\t"+stop_platform_exclude.get(s).get(p).get(e));
				}
			}
			if (stop_platform_name.get(s).size() != stop_platform_nr.get(s).size())
				System.out.println("!warning: stop_platform_name.size() != stop_platform_nr.get("+s+").size() ("+
									stop_platform_name.get(s).size()+" != "+stop_platform_nr.get(s).size()+")");
			if (stop_platform_include.get(s).size() != stop_platform_nr.get(s).size())
				System.out.println("!warning: stop_platform_include.get("+s+").size() != stop_platform_nr.get("+s+").size() ("+
									stop_platform_include.size()+" != "+stop_platform_nr.get(s).size()+")");
			if (stop_platform_exclude.get(s).size() != stop_platform_nr.get(s).size())
				System.out.println("!warning: stop_platform_exclude.get("+s+").size() != stop_platform_nr.get("+s+").size() ("+
									stop_platform_exclude.size()+" != "+stop_platform_nr.get(s).size()+")");
		}
		if (stop_name.size() != stop_id.size())
			System.out.println("!warning: stop_name.size() != stop_id.size() ("+
								stop_name.size()+" != "+stop_id.size()+")");
		if (stop_updated.size() != stop_id.size())
			System.out.println("!warning: stop_updated.size() != stop_id.size() ("+
								stop_updated.size()+" != "+stop_id.size()+")");
		if (stop_platform_nr.size() != stop_id.size())
			System.out.println("!warning: stop_platform_nr.size() != stop_id.size() ("+
								stop_platform_nr.size()+" != "+stop_id.size()+")");
		if (stop_platform_name.size() != stop_id.size())
			System.out.println("!warning: stop_platform_name.size() != stop_id.size() ("+
								stop_platform_name.size()+" != "+stop_id.size()+")");
		if (stop_platform_include.size() != stop_id.size())
			System.out.println("!warning: stop_platform_include.size() != stop_id.size() ("+
								stop_platform_include.size()+" != "+stop_id.size()+")");
		if (stop_platform_exclude.size() != stop_id.size())
			System.out.println("!warning: stop_platform_exclude.size() != stop_id.size() ("+
								stop_platform_exclude.size()+" != "+stop_id.size()+")");
		
		System.out.println("twitter username: "+twitter_username);
		System.out.println("twitter password: "+twitter_password);
	}
}
